03. Smart Pointers

C++ Memory MGMT 04 Smart Pointers A01 Introduction

Smart pointers

Description

Smart pointers are C++ which is designed to improve native safety and performance of memory management of this language. Common problems, such as: memory leaks, lack of memory or failed allocation are captured and processed via smart pointers in C++.

Unique pointer

One implementation of this philosphy is created as unique pointer class, which has main function to prevent memory leakage. It is essentially wrapper class for typical pointer and its operations and actions (allocation, deallocation, incrementation, retrieval of memory address etc.). Main concept of unique pointer stands in a fact that we will get compile time errors with every action which results that two pointers are showing same memory resource. So, when using unique pointers, we are sure that there can only be at most one unique pointer at any one memory location and when that pointer is destroyed (out of scope), the resource is automatically claimed. This approach doesn't prevent actions of moving specified pointer to another location. But when we do that, we are using safe way to move our pointer with usage of function move, which we pass our pointer data.

std::unique_ptr<int> ptr1 (new int);
 // Error: can't copy unique_ptr
std::unique_ptr<int> ptr2 = ptr1;  
 // Works, resource now stored in ptr2
std::unique_ptr<int> ptr2 = std::move(ptr1);

Being said all of these facts, we can conclude that it iss best to use these pointers when we want a single pointer to the memory address that will be reclaimed when that single pointer is destroyed.

Shared pointer

A shared_ptr is a wrapper for default pointers. It is a technique based on reference counting ownership where it maintains the reference count of its initialized pointer in cooperation with all created copies of the shared_ptr. Basically, any time a new pointer points to a memory block an incrementation of the counter happens. Likewise, it decrements when the destructor of the object is called.
Principle of reference counting is a technique of storing the number of references or pointers to a resource such as block of memory.
An object referenced by the contained raw pointer will not be destroyed until reference count is greater than zero, which means that it is not performed until all copies of shared_ptr have been deleted. In essence, shared_ptr should be used when one raw pointer has to be assigned to more owners.

// This is possible without any interference:    
std::shared_ptr<int> ptr1(new int(20));
std::shared_ptr<int> ptr2 = ptr1;

Example

#include <iostream>
#include <memory>
#include <vector>

class testUnique {
  // we didn't need to explicitly disable value-copying
  // with this approach. Now, here we have unique_ptr
  // preventing this behavior
   std::unique_ptr<int> ptr;
public:
   /*
   without unique_ptr we would do something like:
        testUnique(const testUnique&);
        testUnique& operator=(const testUnique&);
   */
   testUnique(int val): ptr(new int(val)){}
   testUnique():ptr(new int(0)) { }
   //getter:
   int getAttr() const {
       return *ptr;
   }
};
int main() {

    // here we can see that we are trying to make container object for shared pointer
    // we are using share pointers for our unique Class
    // using this we can insure that we have multiple pointers point to totally unique object in application
    // which doesn't have any copies
    std::vector<std::shared_ptr<testUnique> > container;
    // we are adding couple objects to our object container (vector):
    container.push_back(std::make_shared<testUnique> (testUnique(2)));
    container.push_back(std::make_shared<testUnique> (testUnique(52)));
    // Printing results:
    for( int i = 0; i < container.size(); i++)
        std::cout << &container[i] << " "
        << (*container[i]).getAttr() << std::endl;
    /* OUTPUT:
        0xd6bce0 2
        0xd6bcf0 52
    */
    return 0;
}